from django import forms
import socket, struct
import re

# integer <-> binary format

def uint2bin(u):
  ''' convert unsigned int to binary format '''
  return struct.pack('>I', u)

def ulong2bin(ul):
  ''' convert unsigned long long to binary format '''
  return struct.pack('>Q', ul)

def bin2uint(b):
  ''' convert 4-bytes binary to unsigned int '''
  return struct.unpack('>I', b)[0]

def bin2ulong(b):
  ''' convert 4-bytes binary to unsigned int '''
  return struct.unpack('>Q', b)[0]

# ip address util

def ip_bin2str(ip_bin):
  '''
    convert 4/16-bytes binary format of ip address to human readable format
  '''
  try:
    if len(ip_bin) == 4:
      return socket.inet_ntop(socket.AF_INET, ip_bin)
    else:
      return socket.inet_ntop(socket.AF_INET6, ip_bin)
  except socket.error as e:
    return ''

def ip_str2bin(ip_str, is_ipv6):
  ''' convert human readable format ip address to 4/16-bytes binary format '''
  try:
    if not is_ipv6:
      return socket.inet_pton(socket.AF_INET, ip_str)
    else:
      return socket.inet_pton(socket.AF_INET6, ip_str)
  except socket.error as e:
    return ''

# prefix util

def pfx_str2binrange(ip_str, psize, is_ipv6):
  '''
    convert human readable ip prefix to binary format NETWORK/BROADCAST range
  '''
  network_bin = ip_str2bin(ip_str, is_ipv6)
  if len(network_bin) == 4:
    network_int = bin2uint(network_bin)
    mask = ((1 << (32 - psize)) - 1)
    broadcast_bin = uint2bin(network_int | mask)
  elif len(network_bin) == 16:
    network_high_int = bin2ulong(network_bin[:8])
    network_low_int = bin2ulong(network_bin[8:])
    mask = ((1 << (128 - psize)) - 1)
    broadcast_high_bin = ulong2bin(network_high_int | (mask >> 64))
    broadcast_low_bin = ulong2bin(network_low_int | (mask & ((1 << 64) - 1)))
    broadcast_bin = broadcast_high_bin + broadcast_low_bin
  else:
    psize = 0 # prefix can not convert
    broadcast_bin = network_bin
  return (network_bin, broadcast_bin)

#

def prefix2range(prefix_dec):
  if not prefix_dec:
    return ""
  if '/' not in prefix_dec:
    return "-1"
  v_pfx = prefix_dec.split('/')
  if not v_pfx or len(v_pfx) != 2 or not v_pfx[1].isdigit():
    return "-1"
  ip_str = v_pfx[0]
  psize = int(v_pfx[1])
  #
  if ip_str.startswith('::ffff:') and '.' in ip_str:
    ip_str = ip_str[7:]
    if psize >= 96:
      psize -= 96
  if ':' in ip_str:
    is_ipv6 = True
  else:
    is_ipv6 = False
  if (is_ipv6 and (psize < 0 or psize > 128)) or (
      (not is_ipv6) and (psize < 0 or psize > 32)):
    return "-1"
  ipbeg_bin, ipend_bin = pfx_str2binrange(ip_str, psize, is_ipv6)
  if ipbeg_bin and ipend_bin:
    return "%s%s %d" % (ipbeg_bin, ipend_bin, psize)
  return "-1"

class AlarmFilterForm(forms.Form):
    topx = forms.IntegerField(min_value = 1, max_value = 99,
        widget=forms.TextInput(attrs={'size':'1'}))
    fig_low = forms.FloatField(min_value = -1.0, max_value = 1.0,
        widget=forms.TextInput(attrs={'size':'1'}))
    fig_high = forms.FloatField(min_value = -1.0, max_value = 1.0,
        widget=forms.TextInput(attrs={'size':'1'}))
    fig_last = forms.IntegerField(min_value = 1, max_value = 120,
        widget=forms.TextInput(attrs={'size':'1'}))
    prefix = forms.CharField(required = False, max_length = 43,
        widget=forms.TextInput(attrs={'size':'20'}))
    AS = forms.IntegerField(required = False, min_value = 1,
        max_value = 4294967295, widget=forms.TextInput(attrs={'size':'1'}))
    rpki = forms.CharField(required = False, max_length = 1,
        widget=forms.TextInput(attrs={'size':'1'}))
    def clean_prefix(self):
        prefix = self.cleaned_data['prefix']
        iprg = prefix2range(prefix)
        if iprg == "-1":
          raise forms.ValidationError("Format Error!")
        return iprg

class AnomalyFilterForm(forms.Form):
    topx = forms.IntegerField(min_value = 1, max_value = 199,
        widget=forms.TextInput(attrs={'size':'1'}))
    prefix = forms.CharField(required = False, max_length = 43,
        widget=forms.TextInput(attrs={'size':'20'}))
    AS = forms.IntegerField(required = False, min_value = 1,
        max_value = 4294967295, widget=forms.TextInput(attrs={'size':'1'}))
    rpki = forms.CharField(required = False, max_length = 1,
        widget=forms.TextInput(attrs={'size':'1'}))
    def clean_prefix(self):
        prefix = self.cleaned_data['prefix']
        iprg = prefix2range(prefix)
        if iprg == "-1":
          raise forms.ValidationError("Format Error!")
        return iprg

class ContactForm(forms.Form):
    name = forms.CharField(max_length=32)
    email = forms.EmailField(required=False, max_length=64)
    message = forms.CharField(required=False, widget=forms.Textarea)
    def clean_message(self):
        message = self.cleaned_data['message']
        if len(message) > 1024:
            raise forms.ValidationError(
                "Message is too long, you can send me an email :)")
        num_words = len(message.split())
        if num_words < 2 or len(message) < 5:
            raise forms.ValidationError("Message is too short :)")
        return message

